package errors

import (
	"encoding/json"
	"fmt"
)

// BizError 业务的错误类型
// 定义了错误码 信息 和 原始 error
// 可以用过 Equels 方法比较 code 的方式比较错误
type BizError struct {
	Code        int64  `json:"code"`
	Message     string `json:"message"`
	SourceError string `json:"source_error,omitempty"`
}

// New 创建新的BizError
func New(code int64, message string) *BizError {
	return &BizError{
		Code:    code,
		Message: message,
	}
}

func NewBizCode(code int64, message string, err error) *BizError {
	if err != nil {
		return &BizError{
			Code:        code,
			Message:     message,
			SourceError: err.Error(),
		}
	}
	return New(code, message)
}

// Error 实现 error 接口的 Error 方法
// 返回 格式化后的错误信息
func (e *BizError) Error() string {
	if e.SourceError != "" {
		return fmt.Sprintf("[biz_error] code: %d, message: %s, source_error: %s", e.Code, e.Message, e.SourceError)
	}
	return fmt.Sprintf("[biz_error] code: %d, message: %s", e.Code, e.Message)
}

func (e *BizError) JSON(err *BizError) string {
	json, _ := json.Marshal(e)
	return string(json)
}

// Equels 比较Error是否为同一种类型
// 比较的内容为error code
// 如果不为 BizError 类型直接返回 false
func (e *BizError) Equels(err error) bool {
	if err == nil {
		return false
	}
	switch bErr := err.(type) {
	case *BizError:
		return e.Code == bErr.Code
	default:
		return false
	}
}

// ConvertBizError 将 error 转为 BizError
// 如果本身不为 BizError 将会转成 Code 为 NotBizError
func ConvertBizError(err error) *BizError {
	if err == nil {
		return nil
	}

	switch e := err.(type) {
	case *BizError:
		return e
	default:
		return &BizError{NotBizError, NotBizErrorMessage, e.Error()}
	}
}
